; $Id: capi-loader.lisp 18 2014-08-05 20:42:21Z admin@en-circle.com $
; Copyright (c) 2014 Peter Vanusanik <admin@en-circle.com>
;
;Permission is hereby granted, free of charge, to any person obtaining a copy
;of this software and associated documentation files (the "Software"), to deal
;in the Software without restriction, including without limitation the rights
;to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
;copies of the Software, and to permit persons to whom the Software is
;furnished to do so, subject to the following conditions:
;
;The above copyright notice and this permission notice shall be included in
;all copies or substantial portions of the Software.
;
;THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
;IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
;FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
;AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
;LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
;OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
;THE SOFTWARE.

#-cl-ass(load "cl-ass.lisp")

(setf *system-classes* (append '(graphics-simulation) *system-classes*))

; Macross

(defmacro defgsimulation (name (&rest slots) environment-class (&rest agent-list) (&rest interface-args))
  (unless interface-args
    (setf interface-args '(:visible-min-width 800 :visible-min-height 600 :title "cl-ass simulation")))
  `(defclass ,name (graphics-simulation) 
     ((environment-class :reader environment-class :initform ',environment-class)
      (agent-list :reader agent-list :initform ',agent-list)
      (init-interface-args :initform ',interface-args  :accessor init-interface-args)
      ,@slots)))

; Classes

(defclass simulation-interface (capi:interface)
  ((simulation :accessor simulation)))

(defclass graphics-simulation (simulation)
  ((import-file :initform '("cl-ass.lisp" "capi-loader.lisp"))
   (init-interface-args :initform nil :accessor init-interface-args)
   (iteration-count :initform 0 :accessor iteration-count)
   (interface :accessor interface)
   (render-panel :accessor render-panel)))

(defmethod initialize-instance :around ((gs graphics-simulation) &key)
  (call-next-method gs)
  (unless *in-export*
    (setf (interface gs) (apply #'make-instance 'simulation-interface (init-interface-args gs)))
    (setf (simulation (interface gs)) gs)
    (make-interface gs)
    (capi:display (interface gs))
    (initialize-simulation gs)))

(defmethod make-interface ((gs graphics-simulation))
  (let* ((it-count-label (make-instance 'capi:title-pane 
                                        :visible-max-width nil
                                        :text (make-iteration-text 0)))
         (spinner (make-instance 'capi:text-input-range 
                                 :value 1
                                 :start 1
                                 :end 10000000))
         (it-button (make-instance 'capi:push-button 
                                   :data "Iterate"
                                   :callback #'(lambda (&rest args)
                                                 (iterate gs (capi:text-input-range-value spinner))
                                                 (setf (capi:title-pane-text it-count-label)
                                                       (make-iteration-text (iteration-count gs))))))
         (reset-button (make-instance 'capi:push-button 
                                      :data "Reset"
                                      :callback #'(lambda (&rest args) 
                                                    (initialize-simulation gs)
                                                    (setf (capi:title-pane-text it-count-label)
                                                          (make-iteration-text 0)))))
         (spinner-text (make-instance 'capi:title-pane 
                                 :text "Iterate amount: "))
         (container-controls (make-instance 'capi:row-layout
                                            :description (list spinner-text spinner it-button
                                                               it-count-label reset-button)))
         (graphics-panel (make-instance 'capi:output-pane
                                        :visible-max-width 800
                                        :visible-max-height 600
                                        :display-callback (lambda (pane x y width height)
                                                            (declare (ignore x y width height))
                                                            (clear-pane gs pane)
                                                            (render-pane gs pane))))
         (container (make-instance 'capi:column-layout
                                   :description (list container-controls graphics-panel))))
    (let ((interface (interface gs)))
      (setf (capi:pane-layout interface) container)
      (setf (render-panel gs) graphics-panel))))

(defmethod initialize-simulation :around ((gs graphics-simulation))
  (setf (iteration-count gs) 0)
  (call-next-method gs)
  (gp:invalidate-rectangle (render-panel gs)))
      
(defmethod iterate :around ((gs graphics-simulation) &optional (itcount 1))
  (incf (iteration-count gs) itcount)
  (call-next-method gs itcount)
  (gp:invalidate-rectangle (render-panel gs)))

; rendering methods
(defgeneric clear-pane (simulation renderer)
  (:documentation "Clears the renderer"))

(defgeneric render-pane (simulation renderer)
  (:documentation "Should draw the state of simulation to the renderer"))

(defmethod clear-pane ((gs graphics-simulation) renderer)
  )

(defmethod render-pane ((gs graphics-simulation) renderer)
  )

; Functions

(defun make-iteration-text (cnt)
  (format nil "Current iteration: ~A" cnt))

